package com.zbkj.crmeb.order.pprocess;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import com.zbkj.crmeb.chant.request.PurchaseProductRequest;
import com.zbkj.crmeb.enums.RoleEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.constants.Constants;
import com.constants.WeChatConstants;
import com.crmeb.core.exception.CrmebException;
import com.huifu.adapay.Adapay;
import com.huifu.adapay.model.MerConfig;
import com.huifu.adapay.model.Payment;
import com.huifu.adapay.model.Refund;
import com.zbkj.crmeb.finance.model.UserRecharge;
import com.zbkj.crmeb.finance.service.UserRechargeService;
import com.zbkj.crmeb.finance.service.process.IRechargeOrderProcess;
import com.zbkj.crmeb.front.request.OrderCreateRequest;
import com.zbkj.crmeb.front.request.UserRechargeRequest;
import com.zbkj.crmeb.front.response.OrderPayResponse;
import com.zbkj.crmeb.merchant.api.request.BuyMemberRequest;
import com.zbkj.crmeb.store.model.StoreOrder;
import com.zbkj.crmeb.store.model.StoreOrderInfo;
import com.zbkj.crmeb.store.request.StoreOrderRefundRequest;
import com.zbkj.crmeb.store.service.StoreOrderService;
import com.zbkj.crmeb.system.service.SystemConfigService;
import com.zbkj.crmeb.system.service.SystemGroupDataService;
import com.zbkj.crmeb.system.vo.SystemGroupDataRechargeConfigVo;
import com.zbkj.crmeb.user.service.UserService;

import lombok.extern.slf4j.Slf4j;

/**
 * 汇付国内支付(目前弃用)
 * @author daigb
 * @date:  2022-07-25 13:38
 */
@Slf4j
@Service("adapayCnPayOrderProcess")
public class AdapayCnPayOrderProcess extends AbstractOrangePayOrderProcess
		implements IRechargeOrderProcess/*, CommandLineRunner*/ {
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private UserService userService;
    @Autowired
    private StoreOrderService storeOrderService;
    @Autowired
    private SystemGroupDataService systemGroupDataService;
    @Autowired
    private UserRechargeService userRechargeService;
    
    private MerConfig merConfig;
    
    @Value("${adapay.cn.apiKey}")
    private String apiKey;
    @Value("${adapay.cn.mockApiKey}")
    private String mockApiKey;
    @Value("${adapay.cn.rsaPrivateKey}")
    private String rsaPrivateKey;
    // 可能需要做成动态配置项
    @Value("${adapay.cn.appId}")
	private String appId;
    @Value("${productType.merchantId}")
    private Integer productTypeMerchantId;
    
    /**
     * 配置初始化
     */
	/*@Override
	public void run(String... args) {
		try {
	    	merConfig = new MerConfig();
	        merConfig.setApiKey(apiKey);
	        merConfig.setApiMockKey(mockApiKey);
	        merConfig.setRSAPrivateKey(rsaPrivateKey);
			Adapay.initWithMerConfig(merConfig);
			log.info("--------------- 初始化汇付国内支付完成 ---------------");
		} catch (Exception e) {
			e.printStackTrace();
			log.error("--------------- 初始化汇付国内支付失败: {} ---------------", e);
		}
	}*/
	
    /**
     * 创建订单
     */
    public OrderPayResponse creatPayOrder(String key, OrderCreateRequest orderRequest, String ip) {
    	// 创建订单数据
        OrderPayResponse orderPayResponse = new OrderPayResponse();
        StoreOrder storeOrder = super.createOrder(key, orderRequest, ip);
        orderPayResponse.setStatus("ADAPAY_CN_PAY");
        orderPayResponse.addExtend("orderId",storeOrder.getOrderId());
        // 下单
        // TODO DIDIOK 支付11
		Map<String, Object> result = payPayment(storeOrder, ip, Constants.SERVICE_PAY_TYPE_ORDER);

        result.put("orderId", storeOrder.getOrderId());
        orderPayResponse.setResult(result);
        return orderPayResponse;
    }
    
	/**
	 * 重新支付
	 */
    @Override
    public Map<String, Object> toPayOrder(StoreOrder order, String ip) {
        //支付调用请求
    	Map<String, Object> resultMap = new HashMap<>();
    	Map<String, Object> result = payPayment(order, ip, Constants.SERVICE_PAY_TYPE_ORDER);

    	resultMap.put("orderId", order.getOrderId());
    	resultMap.put("data", result);
    	resultMap.put("status", "ADAPAY_CN_PAY");
        
        return resultMap;
    }
    
    /**
     * 退款
     */
    @Override
    public boolean refund(StoreOrderRefundRequest request, StoreOrder storeOrder, StoreOrderInfo storeOrderInfo) {
    	// 直接退款情况
        if(null == request.getAmount() || request.getAmount().compareTo(BigDecimal.ZERO)==0){
            return goOnRefund(request, storeOrder,storeOrderInfo);
        }
        try {
        	// 创建退款请求
            LocalDateTime time = LocalDateTime.now();
            Map<String, Object> refundParams = new HashMap<String, Object>(3);
            refundParams.put("refund_amt", request.getAmount().setScale(2, BigDecimal.ROUND_HALF_UP));
            refundParams.put("app_id", appId);
            refundParams.put("refund_order_no", storeOrder.getOrderId() + time.getHour() + "" + time.getMinute() + "" + time.getSecond());
    		log.info("--------------- 汇付国内支付退款原始数据: {} ---------------", JSON.toJSONString(refundParams));
    		
            Map<String, Object> refund = Refund.create(storeOrder.getOutOrderId(), refundParams);
    		log.info("--------------- 汇付国内支付退款返回数据: {} ---------------", JSON.toJSONString(refund));
    		// 退款状态(不代表实际到账状态)
    		if("failed".equals(refund.get("status").toString())) {
            	String msg = refund.get("error_msg") + "";
            	storeOrderStatusService.saveRefund(storeOrderInfo.getOrderId(),storeOrderInfo.getChildOrderNumber(), request.getAmount(), "失败,错误信息:" + msg, request.getType() == 1);
                throw new CrmebException(msg);
    		} else {
    			return goOnRefund(request, storeOrder,storeOrderInfo);
    		}
            
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return false;
    }
    
    /**
     * 购买会员
     */
    @Override
    public Object buyMember(BuyMemberRequest request) {
    	// 虚拟订单对象
        StoreOrder order = new StoreOrder();
        order.setMerId(request.getMerId());
        order.setOrderId(request.getOrderNo());
        order.setUid(request.getUid());
        order.setPayPrice(request.getPrice());
        order.setTotalNum(1);
    	
        //支付调用请求
    	Map<String, Object> resultMap = new HashMap<>();;
        Map<String, Object> result = payPayment(order, request.getClientIp(), Constants.SERVICE_PAY_TYPE_MEMBER);
        result.put("order_id",request.getOrderNo());
        resultMap.put("data", result);
        resultMap.put("status", "ADAPAY_CN_PAY");
        
        return resultMap;
    }

    @Override
    public Map<String, Object> purchaseProduct(PurchaseProductRequest purchaseProductRequest, String ip) {
        // 虚拟订单
        StoreOrder storeOrder = new StoreOrder();
        storeOrder.setMerId(productTypeMerchantId);
        storeOrder.setOrderId(purchaseProductRequest.getOrderNo());
        storeOrder.setPayPrice(RoleEnum.getEnumByCode(purchaseProductRequest.getProductType()).getPrice());
        storeOrder.setTotalNum(1);
        storeOrder.setPayType(Constants.PAY_TYPE_WE_CHAT_NATIVE);

        // 支付调用请求
        Map<String, Object> resultMap = new HashMap<>();
        Map<String, Object> result = payPayment(storeOrder, ip, Constants.SERVICE_PAY_TYPE_PRODUCT);
        result.put("order_id", purchaseProductRequest.getOrderNo());
        resultMap.put("data", result);
        resultMap.put("status", "ADAPAY_DEGREE_PAY");

        return resultMap;
    }

    /**
     * 在线充值
     */
    @Override
    public Map<String, Object> rechage(UserRechargeRequest request) {
        request.setPayments(Constants.PAY_TYPE_ADAPAY_CN);
        // 验证金额是否为最低金额
        BigDecimal rechargeMinAmount = new BigDecimal(systemConfigService.getValueByKeyException(Constants.CONFIG_KEY_RECHARGE_MIN_AMOUNT));
        if(0 < rechargeMinAmount.compareTo(request.getPrice())){
            throw new CrmebException("充值金额不能低于" + rechargeMinAmount);
        }
        // 获取充值模板
        if(request.getGroupDataId() > 0){
            SystemGroupDataRechargeConfigVo systemGroupData = systemGroupDataService.getNormalInfo(request.getGroupDataId(), SystemGroupDataRechargeConfigVo.class);
            if(null == systemGroupData){
                throw new CrmebException("您选择的充值方式已下架");
            }
            //售价和赠送
            request.setPrice(systemGroupData.getPrice());
            request.setGivePrice(BigDecimal.ZERO);
        }
        //生成系统订单
        request.setUserId(userService.getUserIdException());
        UserRecharge userRecharge = userRechargeService.create(request);

    	// 虚拟订单对象
        StoreOrder order = new StoreOrder();
        order.setMerId(request.getMerId());
        order.setOrderId(userRecharge.getOrderId());
        order.setUid(request.getUserId());
        order.setPayPrice(request.getPrice());
        order.setTotalNum(1);
        //支付调用请求
        Map<String, Object> resultMap = new HashMap<>();
    	Map<String, Object> result = payPayment(order, request.getClientIp(), Constants.SERVICE_PAY_TYPE_RECHARGE);
    	resultMap.put("orderId", order.getOrderId());
    	resultMap.put("data", result);
    	resultMap.put("status", "ADAPAY_DEGREE_PAY");
    	resultMap.put("type", request.getFromType());
        
        return resultMap;
    }

    /**
     * 二维码充值
     */
    @Override
    public UserRecharge createImgRecharge(BigDecimal price) {
        return null;
    }
    
    /******************************** 以下为工具方法 ******************************/
    /**
     * 订单实际下单方法
     * @author daigb
     * @date:  2022-07-25 14:41
     */
    private Map<String, Object> payPayment(StoreOrder order, String ip, String ex1) {
		// 下单结果
		Map<String, Object> result = new HashMap<>();
    	// 查询是否同笔订单(已经下单则使用原先支付信息)
    	StoreOrder existOrder = storeOrderService.getByOrderId(order.getOrderId());
    	if(null != existOrder && StringUtils.isNotBlank(existOrder.getBackParam())) {
            log.info("--------------- 汇付国内支付交易, 查询到已存在原始交易请求, 直接返回：{} ---------------", JSON.toJSONString(existOrder));
			result.put("pay_info", JSON.parseObject(existOrder.getBackParam()));
			result.put("result", "SUCCESS");
			
			return result;
    	}
    	
        // 回调地址
        String domain = systemConfigService.getValueByKeyException(WeChatConstants.DOMAIN);
        // 参数组装
        Map<String, Object> paymentParams = new HashMap<>(9);
        paymentParams.put("app_id", appId);
        paymentParams.put("order_no", order.getOrderId());
        paymentParams.put("pay_channel", "wx_lite");
        paymentParams.put("pay_amt", order.getPayPrice().setScale(2, BigDecimal.ROUND_HALF_UP));
        paymentParams.put("goods_title", "goods");
        paymentParams.put("goods_desc", "description");
        paymentParams.put("description", ex1);
        paymentParams.put("notify_url", domain + WeChatConstants.PAY_NOTIFY_API_URI_ADAPAY_CN); // 回调地址
        paymentParams.put("expend", "{\"open_id\":\"" + userService.getInfoToken() + " \"}");
        log.info("--------------- 汇付国内支付交易, 请求参数：{} ---------------", JSON.toJSONString(paymentParams));

        // 实际下单
        Map<String, Object> payment = new HashMap<>();
		result.put("result", "ERROR");
        try {
            // TODO DIDIOK 支付12
            payment = Payment.create(paymentParams);
            log.info("--------------- 汇付国内支付交易, 返回数据：{} ---------------", JSON.toJSONString(payment));
            JSONObject payInfo = JSON.parseObject(payment.get("expend").toString()).getJSONObject("pay_info");
			result.put("pay_info", payInfo);
			result.put("result", "SUCCESS");
			
			// 保留原始下单参数
			boolean backStatus = storeOrderService.update(Wrappers.<StoreOrder>lambdaUpdate()
					.eq(StoreOrder :: getOrderId, order.getOrderId())
					.set(StoreOrder :: getBackParam, payInfo.toString())
					);
			if(backStatus) {
	            log.info("--------------- 汇付国内支付交易, 保存下单原始请求参数：{} ---------------", payInfo.toString());
			}
        } catch (Exception e) {
            log.error("--------------- 汇付国内支付交易, 异常：{} ---------------", e);
            e.printStackTrace();
            return result;
        }
        
        return result;
    }

}
